﻿#include <QPainterPath>
#include <QPainterPathStroker>

#include "connectline.h"
#include "plcelement.h"

ConnectLine::ConnectLine(PlcElement *startItem, Side startSide,  PlcElement *endItem, Side endSide, QGraphicsItem *parent)
    : QGraphicsLineItem(parent)
    , startItem_(startItem)
    , endItem_(endItem)
    , startSide_(startSide)
    , endSide_(endSide)
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setPen(QPen(color_, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    updatePosition();
}

// 元素-锚点
ConnectLine::ConnectLine(PlcElement *startItem, Side startSide, const QPointF& endAnchorScenePos, QGraphicsItem *parent)
    : QGraphicsLineItem(parent)
    , startItem_(startItem)
    , endItem_(nullptr)
    , startSide_(startSide)
    , endSide_(LEFT)
    , endIsAnchor_(true)
    , endAnchorScenePos_(endAnchorScenePos)
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setPen(QPen(color_, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    updatePosition();
}

int ConnectLine::type() const
{
    return Type;
}

void ConnectLine::setPolylineMode(bool on, const QPointF& bendPoint)
{
    polyline_ = on;
    bend_ = bendPoint;
    update(); // 触发重绘
}

void ConnectLine::updatePosition() {
    // 允许一端为锚点
    if (!startItem_ && !startIsAnchor_) return;
    if (!endItem_   && !endIsAnchor_)   return;

    QPointF startPoint;
    if (startIsAnchor_)
    {
        startPoint = startAnchorScenePos_;
    }
    else
    {
        QPointF localStart = (startSide_ == RIGHT)
        ? startItem_->rightConnectionPoint()
        : startItem_->leftConnectionPoint();
        startPoint = startItem_->mapToScene(localStart);
    }

    QPointF endPoint;
    if (endIsAnchor_)
    {
        endPoint = endAnchorScenePos_;
    }
    else
    {
        QPointF localEnd = (endSide_ == RIGHT)
        ? endItem_->rightConnectionPoint()
        : endItem_->leftConnectionPoint();
        endPoint = endItem_->mapToScene(localEnd);
    }

    setLine(QLineF(startPoint, endPoint));
}

PlcElement *ConnectLine::startItem() const
{
    return startItem_;
}

PlcElement *ConnectLine::endItem() const
{
    return endItem_;
}

bool ConnectLine::isPolyline() const
{
    return polyline_;
}

QPointF ConnectLine::bendPoint() const
{
    return bend_;
}

QPointF ConnectLine::startAnchorScenePos() const
{
    return startAnchorScenePos_;
}

QPointF ConnectLine::endAnchorScenePos() const
{
    return endAnchorScenePos_;
}

ConnectLine::Side ConnectLine::endSide() const
{
    return endSide_;
}

ConnectLine::Side ConnectLine::startSide() const
{
    return startSide_;
}

bool ConnectLine::startIsAnchor()
{
    return startIsAnchor_;
}

bool ConnectLine::endIsAnchor()
{
    return endIsAnchor_;
}

// 绘制连接线，直线或折线
void ConnectLine::drawConnection(QPainter *painter) const
{
    const QPointF p1 = line().p1();
    const QPointF p2 = line().p2();
    if (polyline_)
    {
        // L 形：p1 -> bend_ -> p2
        painter->drawLine(QLineF(p1, bend_));
        painter->drawLine(QLineF(bend_, p2));
    }
    else
    {
        painter->drawLine(line());
    }
}

void ConnectLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
    Q_UNUSED(option);
    Q_UNUSED(widget);

    // 如果两端都是元素，保持原来的碰撞过滤
    if (!startIsAnchor_ && !endIsAnchor_)
    {
        if (startItem_ && endItem_ && startItem_->collidesWithItem(endItem_)) return;
    }

    painter->setPen(pen());
    drawConnection(painter);

    if (isSelected())
    {
        painter->setPen(QPen(Qt::red, 1, Qt::DashLine));
        drawConnection(painter);
    }
}

QPainterPath ConnectLine::shape() const
{
    // 构造“几何路径”：直线或折线（p1 -> bend_ -> p2）
    const QPointF p1 = line().p1();
    const QPointF p2 = line().p2();

    QPainterPath path;
    path.moveTo(p1);
    if (polyline_)
    {
        path.lineTo(bend_);
        path.lineTo(p2);
    }
    else
    {
        path.lineTo(p2);
    }

    // 用描边器把可点选的“粗度”做出来
    QPainterPathStroker stroker;
    double w = pen().widthF();                 // 画笔宽度
    if (w <= 0) w = 1.0;                      // cosmetic pen
    // 适当放大可点击范围，避免细线难点中（比如 6~8px）
    stroker.setWidth(std::max<double>(w, 8.0));
    stroker.setCapStyle(pen().capStyle());
    stroker.setJoinStyle(pen().joinStyle());

    return stroker.createStroke(path);
}

QRectF ConnectLine::boundingRect() const
{
    // 用 shape 的包围盒，保证第二段也在包围框内
    return shape().controlPointRect();
}
